<?php
/**
 * Created by JetBrains PhpStorm.
 * User: xiaobai
 * Date: 13-5-24
 * Time: 上午10:18
 * To change this template use File | Settings | File Templates.
 */
class Mobility_ip_model extends CI_Model {

    private $_write_db;
    private $_status_field_suffix_name = '_status';
    private $_use_count_field_suffix_name = '_use_count';
    private $_lose_time_field_suffix_name = '_lose_time';
    function __construct()
    {
        parent::__construct();
        $this->load->library('error_code_library');
        $this->load->database();
        $this->_write_db = $this->load->database('master', TRUE);
    }

    public function create_mobility_ip($ip = NULL, $source = 0, $port = 80) {
        $data = array(
            'ip'        => $ip ,
            'port'      => $port,
            'ctime'     => time() ,
            'status'    => 1,
            'use_count' => 0,
            'source'    => $source
        );
        $this->_write_db->insert('mobility_ip', $data);
        $mobility_ip_id = $this->_write_db->insert_id();
        $this->create_mobility_ip_error($mobility_ip_id,$source);
    }

    public function get_mobility_ip($platform) {
        $adsl_life = $this->config->item('adsl_life');
        $statue_field_name = $platform.$this->_status_field_suffix_name;
        $this->db->select('id, ip, port');
        $this->db->from('mobility_ip');
        $this->db->where('status', 1);
        $this->db->where('source <', 40);
        /**
         * 为了保证查询到的ADSL IP，可以完成本次抓取请求，加入时间显示
         * 可用ADSL IP的创建时间 必须 大于等于 [当前时间 - (ADSL拨号频率:120秒 - (CURL超时时间:10秒 + ADSL完成拨号占用的时间:20秒))]
         */
        if($adsl_life !== 0) {
            $need_adsl_time_point = time() - $adsl_life;
            $this->db->where('ctime >= '.$need_adsl_time_point, NULL);
        }
        //按平台可用性获取IP
        $this->db->where($statue_field_name, 1);
        $this->db->order_by('use_count ASC');
        $query = $this->db->get();

        if($query->num_rows() <= 0) {
            return $this->error_code_library->getError('system', 'data', 'no_data', 'In Function '. __FUNCTION__);
        } else {
            $result_array = $query->result_array();
            $rand_key = array_rand($result_array);
            return $result_array[$rand_key];
        }
    }

    /**
    * 获取ip更新延时的ip列表
    * 所谓更新延时 是指:IP已经10分钟没有变化
    *
    * @access public
    * @return array $mixed
    */
 	public function get_delayed_list() {
        $time_critical_point = time() - (10 * 60);

		$map['status'] = 1;
		$map['ctime <'] = $time_critical_point;

		if(false == ($query = $this->db->where($map)->get('mobility_ip'))){
			return false;
		}

		return $query->result_array();
    }


    public function get_all_mobility_ip() {
    	$adsl_life = $this->config->item('adsl_life');
    	
        $this->db->select('id, ip, port, ctime');
        $this->db->from('mobility_ip');
        $this->db->where('status', 1);
    
    	/**
    	 * 为了保证查询到的ADSL IP，可以完成本次抓取请求，加入时间显示
    	 * 可用ADSL IP的创建时间 必须 大于等于 [当前时间 - (ADSL拨号频率:120秒 - (CURL超时时间:10秒 + ADSL完成拨号占用的时间:20秒))]
    	*/
    	if($adsl_life !== 0) {
    		$need_adsl_time_point = time() - $adsl_life;
    		$this->db->where('ctime >= '.$need_adsl_time_point, NULL);
    	}else{
    		$need_adsl_time_point = time() - (10 * 60);
    		$this->db->where('ctime >= '.$need_adsl_time_point, NULL);
    	}
    	
        $this->db->order_by('use_count ASC');
        $query = $this->db->get();

        if($query->num_rows() <= 0) {
            return $this->error_code_library->getError('system', 'data', 'no_data', 'In Function '. __FUNCTION__);
        } else {
            $result_array = $query->result_array();
            $rand_key = array_rand($result_array);
            return $result_array[$rand_key];
        }
    }
	/**
	 * $ip_num int 获取IP数目
	*/
    public function get_all_mobility_ips($ip_num) {
    	$adsl_life = $this->config->item('adsl_life');
    	
        $this->db->select('id, ip, port, ctime');
        $this->db->from('mobility_ip');
        $this->db->where('status', 1);
    
    	/**
    	 * 为了保证查询到的ADSL IP，可以完成本次抓取请求，加入时间显示
    	 * 可用ADSL IP的创建时间 必须 大于等于 [当前时间 - (ADSL拨号频率:120秒 - (CURL超时时间:10秒 + ADSL完成拨号占用的时间:20秒))]
    	*/
    	if($adsl_life !== 0) {
    		$need_adsl_time_point = time() - $adsl_life - 65;
    		$this->db->where('ctime >= '.$need_adsl_time_point, NULL);
    	}else{
    		$need_adsl_time_point = time() - (10 * 60);
    		$this->db->where('ctime >= '.$need_adsl_time_point, NULL);
    	}
    	
        $this->db->order_by('use_count ASC');
        $query = $this->db->get();

        if($query->num_rows() <= 0) {
            return $this->error_code_library->getError('system', 'data', 'no_data', 'In Function '. __FUNCTION__);
        } else {
			$result_array = $query->result_array();

			//if($ip_num>=$query->num_rows()){
				return $result_array;
			//}else{
				//return array_slice($result_array,0,$ip_num);
			//}
        }
    }

    public function update_mobility_ip_use_count($id = NULL, $platform) {
        if(is_null($id)) {
            return $this->error_code_library->getError('system', 'params', 'no_must_parameter', 'ID In Function '. __FUNCTION__);
        } else {
            $use_count_field_name = $platform.$this->_use_count_field_suffix_name;
            $this->_write_db->set('use_count', 'use_count+1', FALSE);
            $this->_write_db->set($use_count_field_name, $use_count_field_name.'+1', FALSE);
            $this->_write_db->where('`id` = '.$id);
            $result = $this->_write_db->update('mobility_ip');
        }
    }

    public function label_mobility_ip($id = NULL, $platform) {
        if(is_null($id)) {
            return $this->error_code_library->getError('system', 'params', 'no_must_parameter', 'ID In Function '. __FUNCTION__);
        } else {
            $statue_field_name = $platform.$this->_status_field_suffix_name;
            $lose_time_field_name = $platform.$this->_lose_time_field_suffix_name;
            $this->_write_db->set($statue_field_name, 0);
            $this->_write_db->set($lose_time_field_name, time());
            //标记失败次数
            //$this->_write_db->set($statue_field_name, $statue_field_name.'+1', FALSE);
            $this->_write_db->where('`id` = '.$id);
            $result = $this->_write_db->update('mobility_ip');
        }
    }

    public function label_mobility_ip_by_source($source = NULL) {
        if(is_null($source)) {
            return $this->error_code_library->getError('system', 'params', 'no_must_parameter', 'Source In Function '. __FUNCTION__);
        } else {
            $this->_write_db->set('status', 0);
            $this->_write_db->where('`source` = '.$source);
            $result = $this->_write_db->update('mobility_ip');
        }
    }

    public function create_mobility_ip_error($mobility_ip_id = NULL,$source = null) {
        $this->load->model('universal/Mobility_ip_error_model');
        $this->Mobility_ip_error_model->create_mobility_ip_error($mobility_ip_id,$source);
    }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
    * 更新ip 在指定平台的状态
    *
    * @access public
    * @param int $id 要更新状态IP的id [Must]
    * @param string $platform 要更新状态IP的所属平台 [Must]
    * @param int $status 要更新的状态 1 可用 0 不可用 [Optional]
    * @return string $mixed
    */
    public function update_status($id,$platform,$status = 1) {
		if(empty($id) || empty($platform)){
			log_message('error',"Mobility_ip_model update_status param is error !! id:{$id}--platform:{$platform}");
			return false;
		}

        $statue_field_name = $platform.$this->_status_field_suffix_name;
        $lose_time_field_name = $platform.$this->_lose_time_field_suffix_name;


        $data[$statue_field_name] = $status;
        $data[$lose_time_field_name] = 0;
        //$data['ctime'] = time();

		if(false == ($this->_write_db->where("id",$id)->update('mobility_ip',$data))){
			log_message('error',"Mobility_ip_model update is fail !! sql:".$this->_write_db->last_query());
			return false;
		}

		return true;
    }

    /**
    * 获取被锁定的ip列表
    * ip上报更新延时 的机器将不会再被解锁
    *
    *  adsl_life的意义 是与抓取时 curl_timeout 相对应的,为了解决IP正在用.而机器已拨号的问题，比如场景：
    *  一次请求需要20s.如果我们取IP的时候.不做限定.那有可能取到已经过了115s的IP.这样的话因此机器马上就会换IP..注定此次请求会出错..增加失败率
    *
    * @access public
    * @param string $platform 该ip被封的平台 [Optional]
    * @param int $num 每次取的被封IP列表的个数 [Optional]
    * @return array $rs
    */
    public function get_locked_list($platform = 'sina',$num = 10) {
    	$adsl_life = $this->config->item('adsl_life');
    	$statue_field_name = $platform.$this->_status_field_suffix_name;

    	$map['status'] = 1;
    	$map[$statue_field_name] = 0;

        if($adsl_life !== 0) {
        	//创建时间是 可用时间范围内的
            //$map['ctime >= '] = time() - $adsl_life;
            $map['ctime >= '] = time() - 100;
        }

        if(false == ($query = $this->db->where($map)->get('mobility_ip'))){
			log_message('error',"Mobility_ip_model get_locked_list is fail !! sql:".$this->db->last_query());
			return false;
        }

		//随机取出指定个数
		$locked_list = $query->result_array();
		if(count($locked_list) < $num) return false;

		$rand_key_rs = array_rand($locked_list,$num);

		foreach($rand_key_rs as $rand_key) {
			$rs[] = $locked_list[$rand_key];
		}

		return $rs;
    }
    
    public function get_locked_bozhu_list($platform = 'sina',$num = 10) {
    	$adsl_life = $this->config->item('adsl_life');
    	$statue_field_name = $platform.$this->_status_field_suffix_name;
    
    	$map['status'] = 1;
    	$map[$statue_field_name] = 0;
    	$map['sina_use_count >'] = 5;
    
    	if($adsl_life !== 0) {
    		//创建时间是 可用时间范围内的
    		//$map['ctime >= '] = time() - $adsl_life;
    		$map['ctime >= '] = time() - 240;
    	}
    
    	if(false == ($query = $this->db->where($map)->get('mobility_ip'))){
    		log_message('error',"Mobility_ip_model get_locked_list is fail !! sql:".$this->db->last_query());
    		return false;
    	}
    
    	//随机取出指定个数
    	$locked_list = $query->result_array();
    	if(count($locked_list) < $num) return false;
    

    	$rand_key_rs = array_rand($locked_list,$num);
    
    	foreach($rand_key_rs as $rand_key) {
    		$rs[] = $locked_list[$rand_key];
    	}
    
    	return $rs;
    }

    /**
    * 获取指定平台.可用的 ip 总数
    *
    * @access public
    * @param string $platform 该ip被封的平台 [Optional]
    * @return string $mixed
    */
    public function get_normal_count($platform = 'sina') {
    	if(empty($platform)) $platform = 'sina';

    	$adsl_life = $this->config->item('adsl_life');
    	$statue_field_name = $platform.$this->_status_field_suffix_name;


    	$map['status'] = 1;
    	$map[$statue_field_name] = 1;

 		//adsl_life的意义 是与抓取时 curl_timeout 相对应的,为了解决IP正在用.而机器已拨号的问题，比如场景：
		// 一次请求需要20s.如果我们取IP的时候.不做限定.那有可能取到已经过了115s的IP.这样的话因此机器马上就会换IP..注定此次请求会出错..增加失败率
        if($adsl_life !== 0) {
            $map['ctime >= '] = time() - $adsl_life;
        }

		return $this->db->where($map)->from('mobility_ip')->count_all_results();
    }

    /**
    * 获取当前adsl服务器 上报IP的状况
    *
    * @access public
    * @return array $mixed
    */
    public function get_ip_status() {
    	$sql = "SELECT  `id` ,  `ip` ,  `port` ,  `source` ,  `status` ,  `sina_status` , `http_status` , `use_count` ,  `sina_use_count` , `sina_lose_time` , `ctime` FROM  `mobility_ip` WHERE STATUS =1 ORDER BY  `mobility_ip`.`source` ASC";

    	return $this->db->query($sql)->result_array();
    }

	/**
    * 获取 adsl服务器 在指定时间范围内 变更的ip总数
    *
    * @access public
    * @param array $time_rang_type 要查看的时间范围类别 today 当天  week 本周 month 本月 [Optional]
    * @return string $mixed
    */
    public function get_adsl_ipcount($time_rang_type = 'today') {
		switch ($time_rang_type) {
			case 'today':
				$sql = "SELECT count(*) as c,source FROM  `mobility_ip` WHERE ctime > UNIX_TIMESTAMP( CURDATE( ) ) GROUP BY `source`";
				break;
			case 'week':
				$sql = "SELECT count(*) as c,source FROM  `mobility_ip` WHERE ctime > unix_timestamp(DATE_ADD(CURDATE(), INTERVAL -7 DAY)) GROUP BY `source`";
				break;
			case 'month':
				$sql = "SELECT count(*) as c,source FROM  `mobility_ip` WHERE ctime > unix_timestamp(DATE_ADD(CURDATE(), INTERVAL -30 DAY)) GROUP BY `source`";
				break;
			default:
				$sql = "SELECT count(*) as c,source FROM  `mobility_ip` WHERE ctime > UNIX_TIMESTAMP( CURDATE( ) )  GROUP BY `source`";
				break;
		}

		return $this->db->query($sql)->result_array();
    }

    /**
    * 查看ip的散列程度
    * 如果同一个source的机器..散列度很低则说明 ADSL拨号有问题
    *
    * @access public
    * @param string $source 机器的source编号 [Must]
    * @param array $time_rang_type 要查看的时间范围类别 today 当天  week 本周 month 本月 [Optional]
    * @return array $mixed
    */
    public function get_ip_cardinality($source,$time_rang_type = 'today') {
		if(empty($source)) return false;

		switch ($time_rang_type) {
			case 'today':
				$sql = "SELECT count(*) as c,ip,source FROM  `mobility_ip` WHERE ctime > UNIX_TIMESTAMP( CURDATE( ) ) AND source ={$source} GROUP BY `ip`";
				break;
			case 'week':
				$sql = "SELECT count(*) as c,ip,source FROM  `mobility_ip` WHERE ctime > unix_timestamp(DATE_ADD(CURDATE(), INTERVAL -7 DAY)) AND source ={$source} GROUP BY  `ip`";
				break;
			case 'month':
				$sql = "SELECT count(*) as c,ip,source FROM  `mobility_ip` WHERE ctime > unix_timestamp(DATE_ADD(CURDATE(), INTERVAL -30 DAY)) AND source ={$source} GROUP BY  `ip`";
				break;
			default:
				$sql = "SELECT count(*) as c,ip,source FROM  `mobility_ip` WHERE ctime > UNIX_TIMESTAMP( CURDATE( ) ) AND source ={$source} GROUP BY  `ip`";
				break;
		}

		return $this->db->query($sql)->result_array();
    }
}
